/*
 * Copyright (C) 2003-2010 The Music Player Daemon Project
 * http://www.musicpd.org
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "input_plugin.h"
#include "song_print.h"
#include "song.h"
#include "client.h"
#include "playlist.h"
#include "queue.h"
#include "tag.h"
#include "despotify.h"
#include "input/spotify_input_plugin.h"

int ds_eof = 0;
struct despotify_session* despotify_session=NULL;

struct song * spotify_to_mpd_song(struct track * track)
{
	char uri[200];
	char ds_uri[200];
	char t[10];
	struct song * song;
	struct tag * tag;
	despotify_id2uri(track->track_id, uri);
	sprintf(ds_uri, "spotify://%s", uri);	
	sprintf(t, "%d", track->tracknumber);
	song = song_remote_new(ds_uri);
		
	tag = tag_new();
	tag_begin_add(tag);
	tag_add_item_n(tag, TAG_ARTIST, track->artist->name, strlen(track->artist->name));
	tag_add_item_n(tag, TAG_TITLE, track->title, strlen(track->title));
	tag_add_item_n(tag, TAG_TRACK, t, strlen(t));	
	tag_add_item_n(tag, TAG_ALBUM, track->album, strlen(track->album));
	tag_end_add(tag);
	tag->time = track->length/1000;
	
	song->tag = tag;
		
	return song;
}

void despotify_callback(struct despotify_session* ds, int sig, void* data, void* callback_data)
{
    (void)ds; (void)callback_data; (void)data;/* don't warn about unused parameters */

    switch (sig) {
        case DESPOTIFY_END_OF_PLAYLIST:
            ds_eof = 1;
            break;
    }
}

bool spotify_init(const struct config_param *param, GError **error_r)
{
	(void)param;(void)error_r;
	bool spotify_enable = config_get_bool(CONF_ENABLE_SPOTIFY, false);
	if(spotify_enable)
	{
		char * spotify_user = config_get_string(CONF_SPOTIFY_USER, "nobody");
		char * spotify_passwd = config_get_string(CONF_SPOTIFY_PASSWD, "passwd");
    if (!despotify_init())
    {
			g_warning("despotify_init() failed\n");
			return 0;
		}
		despotify_session = despotify_init_client(despotify_callback, NULL, true, true);
    if (!despotify_session) {
        g_warning("despotify_init_client() failed\n");
        return 0;
    }
    
    if (!despotify_authenticate(despotify_session, spotify_user, spotify_passwd)) {
        g_warning( "Authentication failed: %s\n", despotify_get_error(despotify_session));
        despotify_exit(despotify_session);
        return 0;
    }			
	}
	return 1;
}

struct input_stream *spotify_open(const char *uri, GError **error_r)
{
	(void)error_r;
	char ds_uri[200];
	const char * mime = "audio/spotify";
	if(strncmp(uri, "spotify://", 10)==0)
	{
		sprintf(ds_uri, "spotify:track:%s", uri+10);

		struct link* link = despotify_link_from_uri(ds_uri);
		struct track* track = despotify_link_get_track(despotify_session, link);		
		despotify_play(despotify_session, track, false);
		
		struct input_stream * is = g_new(struct input_stream, 1);
		input_stream_init(is, &input_plugin_spotify, ds_uri);
		is->mime = g_strdup(mime);
		is->ready = true;
		is->seekable = false;
		return is;
	}
	return NULL;
}

struct song * spotify_uri_to_song(char *uri)
{
	char ds_uri[200];
	sprintf(ds_uri, "spotify:track:%s", uri+10);
	struct link* link = despotify_link_from_uri(ds_uri);
	struct track* track = despotify_link_get_track(despotify_session, link);
	return spotify_to_mpd_song(track);
}

size_t spotify_read(struct input_stream *is, void *ptr, size_t size, GError **error_r)
{
	(void)error_r;
	struct pcm_data pcm;
	int rc = despotify_get_pcm(despotify_session, &pcm);
	if(rc == 0)
	{
		if(size >= sizeof(pcm))
		{
			is->offset += sizeof(pcm);
			memcpy(ptr, &pcm, sizeof(pcm));
			return sizeof(pcm);
		}
		else
			g_warning("buffer too low");
	}
	return 0;
}

bool spotify_eof(struct input_stream *is)
{
	(void)is;
	return ds_eof;
}

bool spotify_seek(struct input_stream *is, goffset offset, int whence, GError **error_r)
{
	(void)is;(void)offset;(void)whence;(void)error_r;
	ds_eof = 0;
	return false;
}

void spotify_close(struct input_stream *is)
{
	input_stream_deinit(is);
	despotify_stop(despotify_session);
}

void spotify_exit(void)
{
	despotify_exit(despotify_session);
}

const struct input_plugin input_plugin_spotify = {
	.name = "spotify",
	.init = spotify_init,
	.finish = spotify_exit,
	.open = spotify_open,
	.close = spotify_close,
	.read = spotify_read,
	.eof = spotify_eof,
	.seek = spotify_seek,
	NULL
};

